/*
 * Copyright (C) 2015 The Sven Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package cc.core.util;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonDeserializationContext;
import com.google.gson.JsonDeserializer;
import com.google.gson.JsonElement;
import com.google.gson.JsonParseException;
import com.google.gson.JsonPrimitive;
import com.google.gson.JsonSerializationContext;
import com.google.gson.JsonSerializer;

import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;

/**
 * Created by Tan on 14-3-20.
 * email hellotanm@gmail.com
 */
@SuppressWarnings("unused")
public class JsonUtil {
   
    public static Object parseJson(String json, Class clazz) {
        Gson gson = new GsonBuilder()
        .setPrettyPrinting()
        .registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {

            @Override
            public Date deserialize(final JsonElement json, final Type typeOfT,
                    JsonDeserializationContext context) throws JsonParseException {
                try {
                    return DateUtil.parseDate(json.getAsString());
                } catch (ParseException e) {
                    e.printStackTrace();
                    return null;
                }
            }
        })
        .create();
        return gson.fromJson(json, clazz); 
    }

    public static Object parseJson(String json, Type typeOfT) {
        Gson gson = new GsonBuilder()
        .setPrettyPrinting()
        .registerTypeAdapter(Date.class, new JsonDeserializer<Date>() {

            @Override
            public Date deserialize(final JsonElement json, final Type typeOfT,
                    JsonDeserializationContext context) throws JsonParseException {
                try {
                    return DateUtil.parseDate(json.getAsString());
                } catch (ParseException e) {
                    e.printStackTrace();
                    return null;
                }
            }
        })
        .create();
        return gson.fromJson(json, typeOfT);
    }
    
    public static String generateJson(Object obj) {   
        Gson gson = new GsonBuilder()
        .setPrettyPrinting()
        .registerTypeAdapter(Date.class, new JsonSerializer<Date>() {

            @Override
            public JsonElement serialize(Date date, Type type,
                    JsonSerializationContext ctx) {
                return new JsonPrimitive(DateUtil.format(date));
            }
            
        })
        .create();
        return gson.toJson(obj);
        }

        public static HashMap<String, String> paresEntityToMap(Object entity){

            HashMap<String, String> result = new HashMap<>();

            try{

                Method[] methods = entity.getClass().getDeclaredMethods();

                StringBuilder key = new StringBuilder();

                StringBuilder finalKey = new StringBuilder();

        char c;

        for(Method m : methods) {

            if(m.getName().startsWith("get")) {
                key.setLength(0);
                finalKey.setLength(0);

                key.append(m.getName().replaceAll("get", ""));

                for(int i = 0; i < key.length(); i++){
                    c = key.charAt(i);
                    if(Character.isUpperCase(c)){
                        if(i > 0)
                            finalKey.append("_".concat(String.valueOf(c).toLowerCase()));
                        else
                            finalKey.append(String.valueOf(c).toLowerCase());
                    }else{
                        finalKey.append(c);
                    }
                }
                result.put(finalKey.toString(), String.valueOf(m.invoke(entity)));
            }
        }

        return result;

        }catch(Exception e){
            e.printStackTrace();
        }

        return result;
    }

    public static String pares_(String value){

        String [] keys = value.split("_");

        StringBuilder result = new StringBuilder();
        result.append(keys [0]);

        for(int i = 0; i < keys.length; i++){

            if(i == 0)
                continue;

            result.append(keys[i].substring(0, 1).toUpperCase());

            if(keys[i].length() >= 1)
            result.append(keys[i].substring(1,keys[i].length()));

        }

        return result.toString();

    }

    public static String parseMap(HashMap<String, String> map){

        if(map == null)
            return null;

        StringBuilder json = new StringBuilder();

        json.append("{");

        Iterator<String> iterator = map.keySet().iterator();

        while (iterator.hasNext()){
            String key = iterator.next();
            json.append("\"");
            json.append(pares_(key));
            json.append("\"");
            json.append(":");
            json.append("\"");
            json.append(map.get(key));
            json.append("\"");
            json.append(iterator.hasNext() ? "," : "");

        }

        json.append("}");

        return json.toString();
    }

    public static String parseMap(ArrayList<HashMap<String, String>> maps){

        if(maps.size() == 0)
            return "";

        StringBuilder json = new StringBuilder();

        json.append("[");

        for(HashMap<String, String> map : maps){

            json.append(parseMap(map));
            json.append(",");

        }

        json.setLength(json.length() - 1);

        json.append("]");

        return json.toString();

    }

    public static <T> Object parseMap(ArrayList<HashMap<String, String>> maps, Type type){

        if(type == null)
            return null;

        return parseJson(parseMap(maps), type);

    }

    public static <T> Object parseMap(HashMap<String, String> map, Class<T> type){

        if(type == null)
            return null;

        return parseJson(parseMap(map), type);
    }
}
